#
# iTunesSD.py
#
# Author: Duane Maxwell
# (c) Linspire Inc, 2005
#
#  This program is free software; you can redistribute it and/or modify
#   it under the terms of the GNU General Public License as published by
#  the Free Software Foundation; either version 2 of the License, or
#  (at your option) any later version.
#

import random,os
from iTunesDB import *

class iTunesSD_Base:
	def __init__(self,version=0):
		self.version = version

	def getc(self,f): return f.read(1)	
	def putc(self,f,c): f.write(c)
	def getb(self,f): return ord(f.read(1))
	def putb(self,f,b): f.write(chr(b))

	def get3(self,f):
		return (self.getb(f)<<16)+(self.getb(f)<<8)+self.getb(f)
	
	def put3(self,f,w):
		self.putb(f,(w >> 16) & 0xff)
		self.putb(f,(w >> 8) & 0xff)
		self.putb(f,w & 0xff)

class iTunesSD(iTunesSD_Base):
	def __init__(self,version=0):
		iTunesSD_Base.__init__(self,version)
		self.songs = []
		self.unk1 = 0x010600
		self.unk2 = 0
		self.unk3 = 0
		self.unk4 = 0

	def fromITunesDB(self,root):
		self.songs = []
		db_songs = root.songs().songItems().tracks()
		for db_song in db_songs:
			song = iTunesSD_Song()
			song.fromITunesDB(db_song)
			self.songs.append(song)
		random.shuffle(self.songs)

	def read(self,f,version=0):
		numSongs = self.get3(f)
		self.unk1 = self.get3(f)
		headerSize = self.get3(f)
		if headerSize!=0x12:
			print "iTunesSD.read(): invalid header size"
			return
		self.unk2 = self.get3(f)
		self.unk3 = self.get3(f)
		self.unk4 = self.get3(f)
		for i in xrange(numSongs):
			song = iTunesSD_Song(version)
			song.read(f,version)
			self.songs.append(song)
		return self
			
	def write(self,f,version=0):
		self.put3(f,len(self.songs))
		self.put3(f,self.unk1)
		self.put3(f,0x12)
		self.put3(f,self.unk2)
		self.put3(f,self.unk3)
		self.put3(f,self.unk4)
		for song in self.songs:
			song.write(f,version)
	
	def getPList(self):
		p = {'unk1':self.unk1,'unk2':self.unk2,'unk3':self.unk3,'unk4':self.unk4}
		songs = []
		for song in self.songs:
			songs.append(song.getPList())
		p['songs'] = songs
		return p
	
	def setPList(self,p):
		self.unk1 = p['unk1']
		self.unk2 = p['unk2']
		self.unk3 = p['unk3']
		self.unk4 = p['unk4']
		self.songs = []
		for songp in p['songs']:
			song = iTunesSD_Song()
			song.setPList(songp)
			self.songs.append(song)
		return self
	
class iTunesSD_Song(iTunesSD_Base):
	def __init__(self,version = 0):
		iTunesSD_Base.__init__(self,version)
		self.unk1 = 0x5aa501
		self.startTime = 0
		self.unk2 = 0
		self.unk3 = 0
		self.endTime = 0
		self.unk4 = 0
		self.unk5 = 0
		self.volume = 0x64 # normal volume
		self.fileType = 0x01 # 1=MP3, 2=AAC, 3=WAV
		self.unk6 = 0x200
		self.fileName = u""
		self.shuffleFlag = 1 # 0=skip during shuffle, 1=play during shuffle
		self.bookmarkFlag = 0 # 0=not bookmarkeable, 1=bookmarkeable
		self.unk7 = 0
	
	def fromITunesDB(self,song):
		path = song.location()
		path = '/'.join(path.split(':'))
		#song = iTunesSD_Song()
		self.fileName = path
		(root,ext) = os.path.splitext(self.fileName)
		if ext in ['.m4a','.aac']: self.fileType==2
		if ext in ['.wav']: self.fileType==3

	def read(self,f,version):
		size = self.get3(f)
		if size!=0x22e:
			print "iTunesSD_Song.read: Invalid size %d" % size
			return self
		self.unk1 = self.get3(f)
		self.startTime = self.get3(f)
		self.unk2 = self.get3(f)
		self.unk3 = self.get3(f)
		self.endTime = self.get3(f)
		self.unk4 = self.get3(f)
		self.unk5 = self.get3(f)
		self.volume = self.get3(f)
		self.fileType = self.get3(f)
		self.unk6 = self.get3(f)
		self.fileName = f.read(522)
		self.fileName = unicode(self.fileName.rstrip('\0')+'\0',"utf-16","x")
		self.shuffleFlag = self.getb(f)
		self.bookmarkFlag = self.getb(f)
		self.unk7 = self.getb(f)
		return self
	
	def write(self,f,version):
		self.put3(f,0x22e)
		self.put3(f,self.unk1)
		self.put3(f,self.startTime)
		self.put3(f,self.unk2)
		self.put3(f,self.unk3)
		self.put3(f,self.endTime)
		self.put3(f,self.unk4)
		self.put3(f,self.unk5)
		self.put3(f,self.volume)
		self.put3(f,self.fileType)
		self.put3(f,self.unk6)
		fName = self.fileName.encode('utf-16')[2:]
		while len(fName)<522:
			fName = fName+('\0'*(522-len(fName)))
		f.write(fName)
		self.putb(f,self.shuffleFlag)
		self.putb(f,self.bookmarkFlag)
		self.putb(f,self.unk7)
	
	def getPList(self):
		return {'unk1':self.unk1,'startTime':self.startTime,'unk2':self.unk2,'unk3':self.unk3,
			'endTime':self.endTime, 'unk4':self.unk4,'unk5':self.unk5,'volume':self.volume,
			'fileType':self.fileType,'unk6':self.unk6,'fileName':self.fileName,
			'shuffleFlag':self.shuffleFlag,'bookmarkFlag':self.bookmarkFlag,'unk7':self.unk7}
	
	def setPList(self,p):
		self.unk1 = p['unk1']
		self.startTime = p['startTime']
		self.unk2 = p['unk2']
		self.unk3 = p['unk3']
		self.endTime = p['endTime']
		self.unk4 = p['unk4']
		self.unk5 = p['unk5']
		self.volume = p['volume']
		self.fileType = p['fileType']
		self.unk6 = p['unk6']
		self.fileName = p['fileName']
		self.shuffleFlag = p['shuffleFlag']
		self.bookmarkFlag = p['bookmarkFlag']
		self.unk7 = p['unk7']
		return self

if __name__=='__main__':
	#infile =  "/home/dmaxwell/iPod_Control/iTunes/iTunesDBx"
	infile = "/mnt/sda1/iPod_Control/iTunes/iTunesSD"
	outfile = "/home/dmaxwell/iPod_Control/iTunes/iTunesSD.out"
	outfile = infile
	print "reading"
	f = open(infile,"rb")
	p = iTunesSD().read(f)
	f.close()
	if False: # try rebuilding the iTunesSD from iTunesDB
		infile = "/mnt/sda1/iPod_Control/iTunes/iTunesDB"
		f = open(infile,"rb")
		p1 = mh_atom().atom(f)
		p.fromITunesDB(p1)
	s = ""
	if False: # write out a binary file
		f = FileWriteString()
		p.write(f)
		s = f.asString()
	elif True: # write out an XML file
		pl = p.getPList()
		from PListParser import PListWriter, PListReader
		s =  PListWriter().unparseToString([pl])
	print "writing"
	f = open(outfile,"w")
	f.write(s)
	f.close()
	print "done"
